package com.shuwen.gcdj.service.auth;

import com.shuwen.gcdj.bean.auth.CurrentUserInfoBeanWrap;
import com.shuwen.gcdj.common.annotation.JWTAuth;
import com.shuwen.gcdj.common.constant.Constants;
import com.shuwen.gcdj.common.enums.ErrorCode;
import com.shuwen.gcdj.common.error.ErrorReport;
import com.shuwen.gcdj.dto.account.InitUserDto;
import com.shuwen.gcdj.dto.jwt.JWTVerifyDto;
import com.shuwen.gcdj.service.account.AccountRoleService;
import com.shuwen.gcdj.service.account.AccountService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.util.Optional;

@Service
@AllArgsConstructor
@Slf4j
public class AuthService {

    @Autowired
    private final AccountService accountService;

    @Autowired
    private final AccountRoleService accountRoleService;

    public ErrorCode authJwt(HttpServletRequest request, String jwtToken, JWTAuth auth, boolean skipAuth) {
        // 校验Token
        JWTVerifyDto vo = accountService.validJWTToken(jwtToken);
        if (ErrorReport.hasError(vo.getErrorCode())) {
            log.error("AuthService.authJwt(token = {}, auth = {}) vo = {} error: jwt token解析认证失败", jwtToken, auth, vo);
            return vo.getErrorCode();
        }

        // 设置当前用户信息
        InitUserDto initUserDto = accountService.getInitUserById(vo.getDecodeUserId());
        if (initUserDto == null) {
            log.info("AuthService.authJwt(token = {}, auth = {}) vo = {}, error: 用户不存在", jwtToken, auth, vo);
            return ErrorCode.USER_NOT_EXIST;
        }
        // 设置role
        Optional.ofNullable(accountRoleService.getRoleIdsByUserId(vo.getDecodeUserId())).ifPresent(initUserDto::setRoleIds);
        request.setAttribute(Constants.CURRENT_USER_INFO_REQUEST_KEY, initUserDto);

        // Api鉴权 - 跳过鉴权
        if (skipAuth) {
            log.info("AccountService.authJwt() skip auth = true， 接口访问控制无需鉴权");
            return ErrorCode.SUCCESS;
        }

        // Api鉴权 - ApiCode为空不鉴权
        if (auth.apiCode().isEmpty()) {
            log.info("AuthService.authJwt(token = {}, auth = {}) vo = {} apiCode为空时不校验api权限", jwtToken, auth, vo);
            return ErrorCode.SUCCESS;
        }

        // 接口鉴权
        String apiCode = auth.apiCode();
        String userId = vo.getDecodeUserId();
        ErrorCode apiAccess = accountService.apiAccess(userId, apiCode);
        if (ErrorReport.hasError(apiAccess)) {
            log.error("AuthService.authJwt(jwtToken = {}, auth = {}) error: 【{}】暂无权限【{}】", jwtToken, auth, userId, apiCode);
            return apiAccess;
        }

        return ErrorCode.SUCCESS;
    }

    /**
     * feign token解析+鉴权
     *
     * @param jwtToken String
     * @param apiCode  String
     * @param skipAuth Integer
     * @return CurrentUserInfoBeanWrap
     */
    public CurrentUserInfoBeanWrap feignAuthJwt(String jwtToken, String apiCode, Integer skipAuth) {
        CurrentUserInfoBeanWrap wrap = new CurrentUserInfoBeanWrap();
        wrap.setErrorCode(ErrorCode.SUCCESS);
        if (skipAuth == null) {
            skipAuth = 0;
        }

        // 校验Token
        JWTVerifyDto vo = accountService.validJWTToken(jwtToken);
        if (ErrorReport.hasError(vo.getErrorCode())) {
            log.error("AuthService.feignAuthJwt(token = {}, apiCode = {}) vo = {} error: jwt token解析认证失败", jwtToken, apiCode, vo);
            wrap.setErrorCode(vo.getErrorCode());
            return wrap;
        }

        // 设置当前用户信息
        InitUserDto initUserDto = accountService.getInitUserById(vo.getDecodeUserId());
        if (initUserDto == null) {
            log.info("AuthService.feignAuthJwt(token = {}, apiCode = {}) vo = {}, error: 用户不存在", jwtToken, apiCode, vo);
            wrap.setErrorCode(ErrorCode.USER_NOT_EXIST);
            return wrap;
        }
        wrap.setCurrentUserInfoBean(initUserDto);

        // Api鉴权 - 跳过鉴权
        if (skipAuth == 1) {
            log.info("AccountService.feignAuthJwt() skip auth = true， 接口访问控制无需鉴权");
            wrap.setErrorCode(ErrorCode.SUCCESS);
            return wrap;
        }

        // Api鉴权 - ApiCode为空不鉴权
        if (apiCode == null || apiCode.isEmpty()) {
            log.info("AuthService.feignAuthJwt(token = {}, apiCode = {}) vo = {} apiCode为空时不校验api权限", jwtToken, apiCode, vo);
            wrap.setErrorCode(ErrorCode.SUCCESS);
            return wrap;
        }

        // 接口鉴权
        String userId = vo.getDecodeUserId();
        ErrorCode apiAccess = accountService.apiAccess(userId, apiCode);
        if (ErrorReport.hasError(apiAccess)) {
            log.error("AuthService.feignAuthJwt(jwtToken = {}, apiCode = {}) error: 【{}】暂无权限【{}】", jwtToken, apiCode, userId, apiCode);
            wrap.setErrorCode(apiAccess);
            return wrap;
        }

        return wrap;
    }
}
